package com.ruoyi.boat.tcp.server;

import com.ruoyi.boat.codec.BdCodec;
import com.ruoyi.boat.codec.MessageDecoder;
import com.ruoyi.boat.controller.CommandController;
import com.ruoyi.boat.domain.*;
import com.ruoyi.boat.dto.CmdType;
import com.ruoyi.boat.service.*;
import com.ruoyi.boat.tcp.cache.CommunicationType;
import com.ruoyi.boat.tcp.cache.MyApplicationCache;
import com.ruoyi.boat.tcp.cache.WaveBoat;
import com.ruoyi.boat.utils.ByteUtil;
import com.ruoyi.boat.utils.LocationUtil;
import com.ruoyi.boat.ws.WebsocketService;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.stereotype.Component;

import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

@Component
@Data
public class WaveBoatServer implements ApplicationRunner, ApplicationListener<ContextClosedEvent> {
    private Logger logger = LoggerFactory.getLogger(WaveBoatServer.class);

    @Value("${netty.server.port}")
    private int port;

    @Value("${netty.server.host}")
    private String ip;

    private Channel channel;

    private Integer stationNum = 0x2D & 0xff;

    @Autowired
    private IBoatService boatService;
    @Autowired
    private IPathService pathService;
    @Autowired
    private IPathPointService pathPointService;
    @Autowired
    private IStatusService statusService;
    @Autowired
    private IMeteorDataService meteorDataService;
    @Autowired
    private IAisDataService aisDataService;
    @Autowired
    private IAtmosDataService atmosDataService;
    @Autowired
    private IRadarDataService radarDataService;
    @Autowired
    private IWaveDataService waveDataService;
    @Autowired
    private IAdcpDataService adcpDataService;
    @Autowired
    private ICtdDataService ctdDataService;
    @Autowired
    private IWaterQualityService waterQualityService;
    @Autowired
    private IStatisticService statisticService;
    @Autowired
    private WebsocketService websocketService;
    @Autowired
    private MyApplicationCache myApplicationCache;
    @Autowired
    private ITCommandService commandService;

    @Override
    public void run(ApplicationArguments args) throws Exception {

        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup);
            serverBootstrap.channel(NioServerSocketChannel.class);
            serverBootstrap.localAddress(new InetSocketAddress(ip, this.port));
            serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel socketChannel) throws Exception {
                    ChannelPipeline pipeline = socketChannel.pipeline();
                    pipeline.addLast(new DelimiterBasedFrameDecoder(2048, Unpooled.copiedBuffer("\r\n".getBytes(StandardCharsets.UTF_8))));
                    pipeline.addLast(new SimpleChannelInboundHandler<Object>() {
                        @Override
                        protected void channelRead0(ChannelHandlerContext ctx, Object obj) throws Exception {

                            ByteBuf buf = (ByteBuf) obj;
                            byte[] bdBytes = new byte[buf.readableBytes()];
                            buf.readBytes(bdBytes);
                            String bdStr = new String(bdBytes);

                            byte[] msg = null;
                            if (bdStr.startsWith("$TXXX")) {
                                //北二 4.0（目前在用协议）
                                msg = BdCodec.getRevMsgFromBd4Dot0(bdBytes).getContent();
                                logger.info(ByteUtil.bytesToHex(msg));
                            } else if (bdStr.startsWith("$BDTCI")) {
                                //北三
                                msg = BdCodec.getRevMsgFromBd3(bdStr).getContent();
                            } else if (bdStr.startsWith("$BDTXR")) {
                                //北二 2.1
                                msg = BdCodec.getRevMsgFromBd2Dot1(bdBytes).getContent();
                            } else if (bdStr.startsWith("$FKXX")) {
                                /*北斗模块发送通信报文后没有回复FKXX，建议还是需要有此判断
                                BdRes res = BdCodec.getSendResFromBd4Dot0(bdBytes);
                                myApplicationCache.composeCmdResult(res.isFlag(), res.getMsg(), LocalDateTime.now());*/
                            }else if(bdStr.startsWith("$BDPWI")){
                                //logger.info("收到 BDPWI:" + bdStr);
                            }
                            if (msg != null) {
                                logger.info("收到数据： {}", ByteUtil.bytesToHex(msg, " "));
                                switch (ByteUtil.bytesToHex(Arrays.copyOfRange(msg, 0, 2))) {

                                    case "1003": {
                                        myApplicationCache.setContext(ctx);
                                        logger.info("4g连接");
                                        Status status = MessageDecoder.decode1003(msg);
                                        handleWaveStatus(status);
                                        break;
                                    }
                                    case "1004": {
                                        MeteorData meteorData = MessageDecoder.decode1004(msg);
                                        meteorDataService.insertMeteorData(meteorData);
                                        websocketService.sendMeteorData(meteorData);
                                        break;
                                    }
                                    case "1005": {
                                        AisData aisData = MessageDecoder.decode1005(msg);
                                        aisDataService.insertAisData(aisData);
                                        websocketService.sendAisData(aisData);
                                        break;
                                    }
                                    case "1006": {
                                        AtmosData atmosData = MessageDecoder.decode1006(msg);
                                        atmosDataService.insertAtmosData(atmosData);
                                        websocketService.sendAtmosData(atmosData);
                                        break;
                                    }
                                    case "1007": {
                                        RadarData radarData = MessageDecoder.decode1007(msg);
                                        handleRadar(radarData);
                                        break;
                                    }
                                    case "1008": {
                                        WaveData waveData = MessageDecoder.decode1008(msg);
                                        websocketService.sendWaveData(waveData);
                                        waveDataService.insertWaveData(waveData);
                                        break;
                                    }
                                    case "1009": {
                                        AdcpData adcpData = MessageDecoder.decode1009(msg);
                                        websocketService.sendAdcpData(adcpData);
                                        adcpDataService.insertAdcpData(adcpData);
                                        break;
                                    }
                                    case "100A": {
                                        CtdData ctdData = MessageDecoder.decode100A(msg);
                                        websocketService.sendCtdData(ctdData);
                                        ctdDataService.insertCtdData(ctdData);
                                        break;
                                    }
                                    case "100B": {
                                        WaterQuality waterQuality = MessageDecoder.decode100B(msg);
                                        websocketService.sendWaterQuality(waterQuality);
                                        waterQualityService.insertWaterQuality(waterQuality);
                                        break;
                                    }
                                    case "6912": {
                                        CmdResponse cmdResponse = MessageDecoder.decode6912(msg);
                                        MyApplicationCache.CmdRequest cmdRequest = myApplicationCache.getCmdRequest();
                                        if(cmdRequest == null  || cmdRequest.getSerialNum() != cmdResponse.getSerialNum())
                                            return;
                                        if(cmdRequest.getCmdType().equals(CmdType.PATH_PLANING))
                                            updateRouteInfo(cmdRequest.getRes(),cmdRequest.getBoatCode());

                                        websocketService.sendCmdResponse(cmdRequest);
                                        TCommand commandDto = new TCommand();
                                        commandDto.setResult(cmdResponse.getResult());
                                        commandDto.setId(cmdRequest.getId());
                                        commandService.updateTCommand(commandDto);
                                        return;
                                    }
                                    default:
                                        break;
                                }
                            }
                        }

                        private void updateRouteInfo(CommandController.CmdCreateRes res, String boatCode){
                            WaveBoat boat = myApplicationCache.getWaveBoat(boatCode);
                            //更新航线信息
                            if (res.getPath().getStatus() == RouteStatusEnum.newRoute.getStatus()) {
                                //如果有正在运行的航迹 需要设置为取消状态
                                Path activePath = pathService.selectActivePath(boatCode);
                                if (activePath != null && activePath.getStatus() == RouteStatusEnum.navRoute.getStatus()
                                        && activePath.getEndTime() == null) {
                                    activePath.setStatus(RouteStatusEnum.cancelRoute.getStatus());
                                    pathService.updatePath(activePath);
                                }
                                res.getPath().setStatus(RouteStatusEnum.navRoute.getStatus());
                                res.getPath().setBeginTime(new Date());
                                pathService.updatePath(res.getPath());
                                pathPointService.setPathPointBeSentByIds(
                                        res.getBeSendPoints().stream().map(item -> String.valueOf(item.getId()))
                                                .collect(Collectors.joining(","))
                                );
                                boat.setCurrentPath(res.getPath());
                            } else if (res.getPath().getStatus() == RouteStatusEnum.navRoute.getStatus()) {
                                //更新航迹
                                pathPointService.setPathPointBeSentByIds(
                                        res.getBeSendPoints().stream().map(item -> String.valueOf(item.getId()))
                                                .collect(Collectors.joining(","))
                                );
                                boat.setCurrentPath(res.getPath());
                            }
                        }

                        @Override
                        public void channelActive(ChannelHandlerContext ctx) throws Exception {
                            //myApplicationCache.setContext(ctx);
                            //logger.info("4g连接");
                        }

                        @Override
                        public void channelInactive(ChannelHandlerContext ctx) throws Exception {
                            ChannelHandlerContext currentCtx = myApplicationCache.getContext();
                            if(ctx.equals(currentCtx)){
                                myApplicationCache.setContext(null);
                                logger.info("4g断开");
                            }
                        }

                        @Override
                        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
                            logger.error("出现异常：", cause);
                        }
                    });
                }
            });
            Channel channel = serverBootstrap.bind().sync().channel();
            this.channel = channel;
            logger.info("tcp 服务启动，ip={},port={}", this.ip, this.port);
            channel.closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    private void handleRadar(RadarData radarData) {
        List<String> disanceList = new ArrayList<>();
        List<String> hSpeedList = new ArrayList<>();
        List<String> hDirectionList = new ArrayList<>();
        List<String> ratioList = new ArrayList<>();
        List<String> vSpeedList = new ArrayList<>();
        List<String> dataRateList = new ArrayList<>();
        List<String> sDeviationList = new ArrayList<>();
        List<String> maxSpeedList = new ArrayList<>();
        List<String> minSpeedList = new ArrayList<>();
        List<String> zDeviationList = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            disanceList.add("0");
            hSpeedList.add("0");
            hDirectionList.add("0");
            ratioList.add("0");
            vSpeedList.add("0");
            dataRateList.add("0");
            sDeviationList.add("0");
            maxSpeedList.add("0");
            minSpeedList.add("0");
            zDeviationList.add("0");
        }
        String[] distanceStr = radarData.getDistanceList().split(",");
        String[] hSpeedStr = radarData.getHSpeedList().split(",");
        String[] hDirectionStr = radarData.getHDirectionList().split(",");
        String[] ratioStr = radarData.getRatioList().split(",");
        String[] vSpeedStr = radarData.getVSpeedList().split(",");
        String[] dataRateStr = radarData.getDataRateList().split(",");
        String[] sDeviationStr = radarData.getSDeviationList().split(",");
        String[] maxSpeedStr = radarData.getMaxSpeedList().split(",");
        String[] minSpeedStr = radarData.getMinSpeedList().split(",");
        String[] zDeviationStr = radarData.getZDeviationList().split(",");
        if (radarData.getCurrentIndex() == 1) {
            //收到第一包雷达数据
            for (int i = 0; i < 40; i++) {
                disanceList.set(i, distanceStr[i]);
                hSpeedList.set(i, hSpeedStr[i]);
                hDirectionList.set(i, hDirectionStr[i]);
                ratioList.set(i, ratioStr[i]);
                vSpeedList.set(i, vSpeedStr[i]);
                dataRateList.set(i, dataRateStr[i]);
                sDeviationList.set(i, sDeviationStr[i]);
                maxSpeedList.set(i, maxSpeedStr[i]);
                minSpeedList.set(i, minSpeedStr[i]);
                zDeviationList.set(i, zDeviationStr[i]);
            }
            radarData.setDistanceList(String.join(",", disanceList));
            radarData.setHSpeedList(String.join(",", hSpeedList));
            radarData.setHDirectionList(String.join(",", hDirectionList));
            radarData.setRatioList(String.join(",", ratioList));
            radarData.setVSpeedList(String.join(",", vSpeedList));
            radarData.setDataRateList(String.join(",", dataRateList));
            radarData.setSDeviationList(String.join(",", sDeviationList));
            radarData.setMaxSpeedList(String.join(",", maxSpeedList));
            radarData.setMinSpeedList(String.join(",", minSpeedList));
            radarData.setZDeviationList(String.join(",", zDeviationList));
            radarDataService.insertRadarData(radarData);
            websocketService.sendRadarData(radarData);
        } else if (radarData.getCurrentIndex() == 5) {
            //收到第二包雷达数据
            RadarData radarDataInDB = radarDataService.selectRadarDataByBoatCodeAndCreateTime(radarData.getTime(),radarData.getBoatCode());
            if (radarDataInDB == null) {
                for (int i = 0; i < 40; i++) {
                    disanceList.set(i + 40, distanceStr[i]);
                    hSpeedList.set(i + 40, hSpeedStr[i]);
                    hDirectionList.set(i + 40, hDirectionStr[i]);
                    ratioList.set(i + 40, ratioStr[i]);
                    vSpeedList.set(i + 40, vSpeedStr[i]);
                    dataRateList.set(i + 40, dataRateStr[i]);
                    sDeviationList.set(i + 40, sDeviationStr[i]);
                    maxSpeedList.set(i + 40, maxSpeedStr[i]);
                    minSpeedList.set(i + 40, minSpeedStr[i]);
                    zDeviationList.set(i + 40, zDeviationStr[i]);
                }
                radarData.setDistanceList(String.join(",", disanceList));
                radarData.setHSpeedList(String.join(",", hSpeedList));
                radarData.setHDirectionList(String.join(",", hDirectionList));
                radarData.setRatioList(String.join(",", ratioList));
                radarData.setVSpeedList(String.join(",", vSpeedList));
                radarData.setDataRateList(String.join(",", dataRateList));
                radarData.setSDeviationList(String.join(",", sDeviationList));
                radarData.setMaxSpeedList(String.join(",", maxSpeedList));
                radarData.setMinSpeedList(String.join(",", minSpeedList));
                radarData.setZDeviationList(String.join(",", zDeviationList));
                websocketService.sendRadarData(radarData);
                radarDataService.insertRadarData(radarData);
            } else {
                String[] distanceStrInDb = radarDataInDB.getDistanceList().split(",");
                String[] hSpeedStrInDb = radarDataInDB.getHSpeedList().split(",");
                String[] hDirectionStrInDb = radarDataInDB.getHDirectionList().split(",");
                String[] ratioStrInDb = radarDataInDB.getRatioList().split(",");
                String[] vSpeedStrInDb = radarDataInDB.getVSpeedList().split(",");
                String[] dataRateStrInDb = radarDataInDB.getDataRateList().split(",");
                String[] sDeviationStrInDb = radarDataInDB.getSDeviationList().split(",");
                String[] maxSpeedStrInDb = radarDataInDB.getMaxSpeedList().split(",");
                String[] minSpeedStrInDb = radarDataInDB.getMinSpeedList().split(",");
                String[] zDeviationStrInDb = radarDataInDB.getZDeviationList().split(",");
                for (int i = 0; i < 40; i++) {
                    disanceList.set(i, distanceStrInDb[i]);
                    hSpeedList.set(i, hSpeedStrInDb[i]);
                    hDirectionList.set(i, hDirectionStrInDb[i]);
                    ratioList.set(i, ratioStrInDb[i]);
                    vSpeedList.set(i, vSpeedStrInDb[i]);
                    dataRateList.set(i, dataRateStrInDb[i]);
                    sDeviationList.set(i, sDeviationStrInDb[i]);
                    maxSpeedList.set(i, maxSpeedStrInDb[i]);
                    minSpeedList.set(i, minSpeedStrInDb[i]);
                    zDeviationList.set(i, zDeviationStrInDb[i]);
                }
                for (int i = 0; i < 40; i++) {
                    disanceList.set(i + 40, distanceStr[i]);
                    hSpeedList.set(i + 40, hSpeedStr[i]);
                    hDirectionList.set(i + 40, hDirectionStr[i]);
                    ratioList.set(i + 40, ratioStr[i]);
                    vSpeedList.set(i + 40, vSpeedStr[i]);
                    dataRateList.set(i + 40, dataRateStr[i]);
                    sDeviationList.set(i + 40, sDeviationStr[i]);
                    maxSpeedList.set(i + 40, maxSpeedStr[i]);
                    minSpeedList.set(i + 40, minSpeedStr[i]);
                    zDeviationList.set(i + 40, zDeviationStr[i]);
                }
                radarDataInDB.setDistanceList(String.join(",", disanceList));
                radarDataInDB.setHSpeedList(String.join(",", hSpeedList));
                radarDataInDB.setHDirectionList(String.join(",", hDirectionList));
                radarDataInDB.setRatioList(String.join(",", ratioList));
                radarDataInDB.setVSpeedList(String.join(",", vSpeedList));
                radarDataInDB.setDataRateList(String.join(",", dataRateList));
                radarDataInDB.setSDeviationList(String.join(",", sDeviationList));
                radarDataInDB.setMaxSpeedList(String.join(",", maxSpeedList));
                radarDataInDB.setMinSpeedList(String.join(",", minSpeedList));
                radarDataInDB.setZDeviationList(String.join(",", zDeviationList));
                websocketService.sendRadarData(radarDataInDB);
                radarDataService.updateRadarData(radarDataInDB);
            }
        } else {
            //收到第三包雷达数据
            RadarData radarDataInDB = radarDataService.selectRadarDataByBoatCodeAndCreateTime(radarData.getTime(),radarData.getBoatCode());
            if (radarDataInDB == null) {
                for (int i = 0; i < 20; i++) {
                    disanceList.set(i + 80, distanceStr[i]);
                    hSpeedList.set(i + 80, hSpeedStr[i]);
                    hDirectionList.set(i + 80, hDirectionStr[i]);
                    ratioList.set(i + 80, ratioStr[i]);
                    vSpeedList.set(i + 80, vSpeedStr[i]);
                    dataRateList.set(i + 80, dataRateStr[i]);
                    sDeviationList.set(i + 80, sDeviationStr[i]);
                    maxSpeedList.set(i + 80, maxSpeedStr[i]);
                    minSpeedList.set(i + 80, minSpeedStr[i]);
                    zDeviationList.set(i + 80, zDeviationStr[i]);
                }
                radarData.setDistanceList(String.join(",", disanceList));
                radarData.setHSpeedList(String.join(",", hSpeedList));
                radarData.setHDirectionList(String.join(",", hDirectionList));
                radarData.setRatioList(String.join(",", ratioList));
                radarData.setVSpeedList(String.join(",", vSpeedList));
                radarData.setDataRateList(String.join(",", dataRateList));
                radarData.setSDeviationList(String.join(",", sDeviationList));
                radarData.setMaxSpeedList(String.join(",", maxSpeedList));
                radarData.setMinSpeedList(String.join(",", minSpeedList));
                radarData.setZDeviationList(String.join(",", zDeviationList));
                websocketService.sendRadarData(radarData);
                radarDataService.insertRadarData(radarData);
            } else {
                String[] distanceStrInDb = radarDataInDB.getDistanceList().split(",");
                String[] hSpeedStrInDb = radarDataInDB.getHSpeedList().split(",");
                String[] hDirectionStrInDb = radarDataInDB.getHDirectionList().split(",");
                String[] ratioStrInDb = radarDataInDB.getRatioList().split(",");
                String[] vSpeedStrInDb = radarDataInDB.getVSpeedList().split(",");
                String[] dataRateStrInDb = radarDataInDB.getDataRateList().split(",");
                String[] sDeviationStrInDb = radarDataInDB.getSDeviationList().split(",");
                String[] maxSpeedStrInDb = radarDataInDB.getMaxSpeedList().split(",");
                String[] minSpeedStrInDb = radarDataInDB.getMinSpeedList().split(",");
                String[] zDeviationStrInDb = radarDataInDB.getZDeviationList().split(",");
                for (int i = 0; i < 80; i++) {
                    disanceList.set(i, distanceStrInDb[i]);
                    hSpeedList.set(i, hSpeedStrInDb[i]);
                    hDirectionList.set(i, hDirectionStrInDb[i]);
                    ratioList.set(i, ratioStrInDb[i]);
                    vSpeedList.set(i, vSpeedStrInDb[i]);
                    dataRateList.set(i, dataRateStrInDb[i]);
                    sDeviationList.set(i, sDeviationStrInDb[i]);
                    maxSpeedList.set(i, maxSpeedStrInDb[i]);
                    minSpeedList.set(i, minSpeedStrInDb[i]);
                    zDeviationList.set(i, zDeviationStrInDb[i]);
                }
                for (int i = 0; i < 20; i++) {
                    disanceList.set(i + 80, distanceStr[i]);
                    hSpeedList.set(i + 80, hSpeedStr[i]);
                    hDirectionList.set(i + 80, hDirectionStr[i]);
                    ratioList.set(i + 80, ratioStr[i]);
                    vSpeedList.set(i + 80, vSpeedStr[i]);
                    dataRateList.set(i + 80, dataRateStr[i]);
                    sDeviationList.set(i + 80, sDeviationStr[i]);
                    maxSpeedList.set(i + 80, maxSpeedStr[i]);
                    minSpeedList.set(i + 80, minSpeedStr[i]);
                    zDeviationList.set(i + 80, zDeviationStr[i]);
                }
                radarDataInDB.setDistanceList(String.join(",", disanceList));
                radarDataInDB.setHSpeedList(String.join(",", hSpeedList));
                radarDataInDB.setHDirectionList(String.join(",", hDirectionList));
                radarDataInDB.setRatioList(String.join(",", ratioList));
                radarDataInDB.setVSpeedList(String.join(",", vSpeedList));
                radarDataInDB.setDataRateList(String.join(",", dataRateList));
                radarDataInDB.setSDeviationList(String.join(",", sDeviationList));
                radarDataInDB.setMaxSpeedList(String.join(",", maxSpeedList));
                radarDataInDB.setMinSpeedList(String.join(",", minSpeedList));
                radarDataInDB.setZDeviationList(String.join(",", zDeviationList));
                radarDataInDB.setLng(radarData.getLng());
                radarDataInDB.setLat(radarData.getLat());
                radarDataInDB.setLaserStatus(radarData.getLaserStatus());
                radarDataInDB.setAmplifierStatus(radarData.getAmplifierStatus());
                radarDataInDB.setLaserPower(radarData.getLaserPower());
                radarDataInDB.setAmplifierPower(radarData.getAmplifierPower());
                radarDataInDB.setLaserTemp(radarData.getLaserTemp());
                radarDataInDB.setAmplifierTemp(radarData.getAmplifierTemp());
                radarDataInDB.setModuleTemp(radarData.getModuleTemp());
                radarDataInDB.setModuleHumidity(radarData.getModuleHumidity());
                radarDataInDB.setInputVoltage(radarData.getInputVoltage());
                radarDataInDB.setDiskSpace(radarData.getDiskSpace());
                radarDataInDB.setMeasurementStatus(radarData.getMeasurementStatus());
                websocketService.sendRadarData(radarDataInDB);
                radarDataService.updateRadarData(radarDataInDB);
            }
        }
    }

    private void handleWaveStatus(Status status) {
        // 用于统计到达率
        Statistic statistic = new Statistic()
                .setMsgReceived(1)
                .setMsgAll(status.getSerialNum())
                .setBoatCode(status.getBoatCode())
                .setTime(status.getTime());
        // 手动航行 controlMode = 1 自动航行 controlMode = 0
        // 当跑完最后一个航迹点 status 的 destNum = 255 艇之后就开始打转 需要计算它的驻留偏差
        WaveBoat waveBoat = new WaveBoat();
        waveBoat.setStatus(status);
        waveBoat.setCommType(CommunicationType.$4G);
        WaveBoat prev = myApplicationCache.getPrevWaveBoatStatus(status.getBoatCode(), waveBoat);
        if (prev != null) {
            Status prevStatus = prev.getStatus();
            waveBoat.setBoatInfo(prev.getBoatInfo());
            if (status.getControlMode() == 0 && prevStatus.getControlMode() == 0) {
                //自动航行 从点2到点3 开始计算偏差
                if (status.getDestNum() > prevStatus.getDestNum()
                        && prevStatus.getDestNum() >= 2 && status.getDestNum() != 255) {
                    Path currentPath = prev.getCurrentPath();
                    if (currentPath != null && Objects.equals(currentPath.getStatus(), RouteStatusEnum.navRoute.getStatus())) {
                        //存入 缓存
                        //需要做偏差计算 例如 从经过 点2之后开始计算 这个值是 实际经纬度到 1-2点 线段的垂直距离
                        List<PathPoint> pathPointList = currentPath.getPathPointList();
                        PathPoint pointBeforePre = pathPointList.get(status.getDestNum() - 2);
                        PathPoint pointPre = pathPointList.get(status.getDestNum() - 1);
                        double deviation = LocationUtil.calculateDeviation(pointBeforePre.getLng()
                                , pointBeforePre.getLat()
                                , pointPre.getLng(), pointPre.getLat()
                                , status.getLng(), status.getLat());
                        status.setDeviation(deviation);
                        waveBoat.setCurrentPath(currentPath);
                    }
                }
                //航线结束
                if (status.getDestNum() > prevStatus.getDestNum()
                        && status.getDestNum() == 255) {
                    Path currentPath = prev.getCurrentPath();
                    if (currentPath != null && currentPath.getStatus()
                            == RouteStatusEnum.navRoute.getStatus()) {
                        //计算偏差
                        List<PathPoint> pathPointList = currentPath.getPathPointList();
                        PathPoint pointBeforePre = pathPointList.get(pathPointList.size() - 2);
                        PathPoint pointPre = pathPointList.get(pathPointList.size() - 1);
                        double deviation = LocationUtil.calculateDeviation(pointBeforePre.getLng()
                                , pointBeforePre.getLat()
                                , pointPre.getLng(), pointPre.getLat()
                                , status.getLng(), status.getLat());
                        status.setDeviation(deviation);
                        //更新缓存
                        currentPath.setStatus(RouteStatusEnum.completeRoute.getStatus());
                        currentPath.setEndTime(new Date());
                        waveBoat.setCurrentPath(currentPath);
                        //更新数据库
                        Path pathUpdateDto = new Path();
                        pathUpdateDto.setId(currentPath.getId());
                        pathUpdateDto.setStatus(RouteStatusEnum.completeRoute.getStatus());
                        pathUpdateDto.setEndTime(new Date());
                        pathService.updatePath(pathUpdateDto);
                    }
                }
                //开始驻留
                if (Objects.equals(status.getDestNum(), prevStatus.getDestNum())
                        && status.getDestNum() == 255) {
                    Path currentPath = prev.getCurrentPath();
                    if (currentPath != null && currentPath.getStatus()
                            == RouteStatusEnum.completeRoute.getStatus()) {
                        //计算驻留偏差
                        List<PathPoint> pathPointList = currentPath.getPathPointList();
                        PathPoint lastPoint = pathPointList.get(pathPointList.size() - 1);
                        status.setDeviation(LocationUtil.getDistanceOfMeter(status.getLat()
                                , status.getLng(), lastPoint.getLat(), lastPoint.getLng()));
                    }
                }
            }
        } else {
            //第一次上线,记录最近一条 complete 或者 nav的航迹
            Path currentPath = pathService.selectActivePath(status.getBoatCode());
            Boat boatDto = new Boat();
            boatDto.setCode(status.getBoatCode());
            List<Boat> boatInfoList = boatService.selectBoatList(boatDto);
            if (boatInfoList.size() > 0) {
                waveBoat.setBoatInfo(boatInfoList.get(0));
            }
            waveBoat.setCurrentPath(currentPath);
        }
        //更新状态
        myApplicationCache.updateWaveBoat(status.getBoatCode(), waveBoat);
        websocketService.sendStatus(status);
        statusService.insertStatus(status);
        statisticService.insertOrUpdate(statistic);
    }

    @Override
    public void onApplicationEvent(ContextClosedEvent event) {
        if (this.channel != null) {
            channel.close();
        }
    }
}
